<?php

/**
 * Базовый класс модулей.
 *
 */
class Kernel_Module extends Kernel_Filter 
{

    /**
     * Наименование действия фронтенда, соответствующего явно не указанному действию в URL.
     *
     */
    const DEFAULT_ACTION = 'default';

    /**
     * Наименование класса контроллера фронтенда.
     *
     * @var string
     */
    protected $FRONTEND_CONTROLLER = 'Kernel_Controller_Frontend';

    /**
     * Наименование действия на фронтенде, на которое нужно перенаправить агента
     * в случае, если действие явно не указано.
     *
     * @var string
     */
    protected $_default_action = self::DEFAULT_ACTION;

    /**
     * Наименование класса контроллера бэкенда.
     *
     * @var string
     */
    protected $BACKEND_CONTROLLER = 'Kernel_Controller_Backend';

    /**
     * @desc Collection of the names and classes of managers which current
     * module presents in Backend. 
     *
     * @param array
     */
    protected $_managers = array();

    /**
     * Массив модулей, от которых зависит модуль.
     *
     * @var array
     */
    protected $_dependencies = array();

    /**
     * Конструктор.
     *
     */
    public function __construct($params = array()) 
    {
        parent::__construct($params);
        foreach (array_merge(array($this->_getName()), $this->_dependencies) as $package) {
            Kernel_i18n::import($package);
        }
    }

    /**
     * Запускает фильтр — реализует интерфейс фильтра.
     *
     */
    public function process() 
    {
        Application::getMode()->forward($this);
    }

    /**
     * Создает модуль указанного наименования.
     *
     * @param   string  $name
     * @return  Kernel_Module
     * @throws  Kernel_Filter_Exception_NotFound
     */
    static public function factory($name) 
    {
        return Kernel::factory('%s_Module', $name);
    }

    /**
     * Возвращает данные блока c указанным наименованием.
     *
     * @param   string  $name
     * @param   array   $params
     * @return  array
     */
    public function block($name, $params = array()) 
    {
        return Kernel::factory($this->_getName() . '_Block', $name, $params)->getData();
    }

    /**
     * @desc Return backend manager.
     *
     * @param   string  $name
     * @return  Kernel_Manager
     */
    public function getManager($name) 
    {
        if (!array_key_exists($name, $this->_managers)) {
            return null;
        }
        
        $params = $this->_getManagerFilters($name);
        
        $token = Kernel_Token::wrap($this->_managers[$name], 
            !empty($params) ? array('filters' => $params) : array());
        $class = $token->getName();
        return new $class($token->getParams());
    }
    
    /**
    * @desc Return filters list. Used with Kernel_Manager_FilteredList
    * 
    * @param string $name
    * @return array
    */
    protected function _getManagerFilters($name) 
    {
        return array();
    }

    /**
     * Запускает модуль для фронтенда.
     *
     */
    public function frontend() 
    {
        $this->_forward($this->_getFrontController());
    }

    /**
     * Запускает модуль в режиме веб-сервиса.
     *
     */
    public function service() 
    {
        $this->_forward(Application::dummy()->service(array(
            'module' => $this->_getName(),
        )));
    }

    /**
     * Запускает модуль для выполнения задач крона.
     *
     */
    public function cron() 
    {
        // запускаем все крон-компоненты в непонятно каком порядке (исходим из
        // того, комоненты не имеют взаимосвязей)
        foreach ($this->_getComponents('cron') as $class) {
            $this->_forward(new $class);
        }
    }

    /**
     * Возвращает имя модуля, определяя его по наименованию класса, которое
     * составляется по правилу 'Blah_Blah_Blah_ИмяМодуля_Module';
     *
     * @return  string
     */
    protected function _getName() 
    {
        return preg_replace('/.*?([^_]+)_[^_]+$/', '$1', get_class($this));
    }

    /**
     * Возвращает контроллер фронтенда.
     *
     * @return  Kernel_Controller_Frontend
     */
    private function _getFrontController() 
    {
        return new $this->FRONTEND_CONTROLLER(array(
            'module' => $this->_getName(),
            'default' => $this->_default_action,
            'redirect' => $this->_default_action != self::DEFAULT_ACTION,
        ));
    }

    /**
     * Возвращает наименования классов компонентов модуля с указанным префиксом.
     *
     * @param   string  $prefix
     * @return  array
     */
    private function _getComponents($prefix) 
    {
        return Kernel::getClasses($this->_getName()
            . DIRECTORY_SEPARATOR . str_camelize($prefix));
    }
    
}
